package cz.worktracker.controller;

import cz.worktracker.enums.DataSetsEnum;
import cz.worktracker.model.entities.User;

import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
import java.security.Principal;
import java.io.Serializable;
import java.util.logging.Level;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.el.MethodNotFoundException;
import javax.enterprise.context.SessionScoped;
import javax.faces.component.html.HtmlDataTable;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.inject.Inject;
import javax.inject.Named;
import org.hibernate.criterion.Order;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Transaction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;
import java.util.Map;

/**
 * AdminManager
 * Správa registrovaných uživatelů
 * @since 2010-04-28
 * @author musil
 */
@ManagedBean
@SessionScoped
@Named
public class AdminManager extends AbstractManager
                            implements Serializable {

    private static final long SerialVersionUID = 2L;

    private User user;
    private AbstractPaginator paginator;
    private DataModel dataModel;
    private HtmlDataTable usersDataTable;
    private String searchPattern = "";
    private DataSetsEnum DSEnum;
    private int rowsPerPage = DSEnum.ITEMS_PER_PAGE_DEFAULT.getValue();
    private String sortByField = DSEnum.SORT_BY_FIELD.getStringValue();
    private String sortDirection = DSEnum.SORT_DIRECTION.getStringValue();

    private static final String MAIN_ORDERING = "name";

    private static final String NAV_LIST = "list";
    private static final String NAV_EDIT = "editUser";
    private static final String NAV_REDIRECT = "?faces-redirect=true";

    @Inject UserManager userManager;


    /**
     * Constructor
     */
    public AdminManager() { }

    @PostConstruct
    public void construct() {
        init();
    }

    @PreDestroy
    public void destroy() {
        user = null;
        paginator = null;
        dataModel = null;
    }

    private void init() {
        if( user == null ) {
            user = new User();
        }
    }

    /**
     * Method sets current user record for editation.
     * @return
     */
    public String getEdit() {
        setUser( (User) getList().getRowData() );
        
        return NAV_EDIT + NAV_REDIRECT;
    }

    /**
     * Next page.
     */
    public void next() {
        getPaginator().nextPage();
        resetDataModel();
    }

    /**
     * Last page.
     */
    public void last() {
        getPaginator().lastPage();
        resetDataModel();
    }


    /**
     * Previous page.
     */
    public void previous() {
        getPaginator().previousPage();
        resetDataModel();
    }

    /**
     * First page.
     */
    public void first() {
        getPaginator().firstPage();
        resetDataModel();
    }

    /**
     * Retrieves sort params through context and initiates sort.
     */
    public void sort() {
        /**
         * Try to gain params send by <f:param />
         */
        FacesContext context = FacesContext.getCurrentInstance();
        Map requestMap = context.getExternalContext().getRequestParameterMap();
        setSortByField( (String) requestMap.get("by") );
        setSortDirection( (String) requestMap.get("order") );

        resetPagination();
        resetDataModel();

    }
    

    /**
     * Sets sort direction (ascending: asc; descending desc).
     * @param sortDirection
     */
    public void setSortDirection(String sortDirection) {
        this.sortDirection = sortDirection;
    }

        /**
     * Returns field name in JPA entity according which sorting will be provided.
     * @return String
     */
    public String getSortByField() {
        return sortByField;
    }


    /**
     * Sets field name in JPA entity according which sorting will be provided.
     * @param sortByField
     */
    public void setSortByField(String sortByField) {
        this.sortByField = sortByField;
    }

    /**
     * GetRole
     * @deprecated
     * @return
     */
    public String getRole() {
        Principal principal = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();

        return FacesContext.getCurrentInstance().getExternalContext().isUserInRole("ADMIN") + " "
                    + FacesContext.getCurrentInstance().getExternalContext().isUserInRole("USER") + " "
                    + FacesContext.getCurrentInstance().getExternalContext().isUserInRole("NONE");
    }


    public void remove() {
        user = (User) getList().getRowData();

        Transaction tx = getSession().beginTransaction();
        user.setIsActive("n");
        getSession().update( user );
        tx.commit();
        user = null;

        getUsersCount();

        resetPagination();
        resetDataModel();

        System.out.println("delete user");

        // return NAV_LIST + NAV_REDIRECT;
    }

    /**
     * Method nulls reference of paginator.
     */
    public void resetPagination() {
        paginator = null;
    }

    /**
     * Method nulls reference of dataModel.
     */
    private void resetDataModel() {
        dataModel = null;
    }

    /**
     * Returns true if user has ADMIN role.
     * @deprecated
     * @return True if user is admin. Otherwise false.
     */
    public boolean isAdmin() {
        /** Should be reimplemented. */
        return false;
    }


    /**
     * Updates user data.
     * @return String
     */
    public String update() {

        if ( getUser() != null) {
            try {
                Transaction tx = getSession().beginTransaction();
                getSession().update( getUser() );
                getUser().setPassword( RegisterBean.MD5( getUser().getPassword() ) );
                tx.commit();
                init();
            } catch (Exception e) {
                getLogger(getClass()).log(Level.SEVERE, "Error on try to save User: ", e);
                addMessage("Error on try to save User");
                return null;
            }
        }

        return "main";
    }


    /**
     * Returns DataModel object.
     * @return
     */
    public DataModel getList() {
        if( dataModel == null ) {
            dataModel = getPaginator().createPageDataModel();
        }

        return dataModel;
    }

    /**
     * Returns page switcher and override abstract methods from AbstractPaginator.
     * @return Paginator object.
     */
    public AbstractPaginator getPaginator() {
        if( paginator == null ) {
            paginator = new AbstractPaginator(rowsPerPage) {

               /*
                * While creating a new instance we have to implement abstract
                * methods defined in AbstractPaginator class.
                */

                @Override
                public int getItemsCount() {
                    return getUsersCount();
                }

                @Override
                public DataModel createPageDataModel() {
                    ListDataModel list = null;

                    try {
                        Transaction tx = getSession().beginTransaction();
                        Criteria ct = getSession().createCriteria(User.class);

                        ct.add( Restrictions.eq( "isActive", "y" ) );

                        if( getSortDirection().equalsIgnoreCase( "asc" ) ) {
                            ct.addOrder( Order.asc( getSortByField()) );
                        } else {
                            ct.addOrder( Order.desc( getSortByField()) );
                        }

                        ct.setFirstResult(getPageFirstItem());
                        ct.setMaxResults(getPageSize());
                        list = new ListDataModel(ct.list());
                        tx.commit();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    return list;
                }
            };
        }

        return paginator;
    }

    /**
     * Returns sort direction (ascending: asc; descending desc).
     * @return String
     */
    public String getSortDirection() {
        return sortDirection;
    }

    /**
     * Returns searched string.
     * @return String
     */
    public String getSearchPattern() {
        return searchPattern;
    }

    /**
     * Returns customers count.
     * @return int means customers count.
     */
    public int getUsersCount() {
        Transaction tx = getSession().beginTransaction();
        String hql = "select count(*) from User as user where user.isActive='y' ";
        return ( (Long) (getSession().createQuery(hql).iterate().next()) ).intValue();
    }

    public HtmlDataTable getUsersDataTable() {
        return usersDataTable;
    }

    public void setUsersDataTable(HtmlDataTable usersDataTable) {
        this.usersDataTable = usersDataTable;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public DataModel getDataModel() {
        return dataModel;
    }

    public void setDataModel(DataModel dataModel) {
        this.dataModel = dataModel;
    }



}
